package uprobe

import (
	"eSymCounter/config"
	"eSymCounter/utils"
	"log"

	"github.com/cilium/ebpf/link"
)

func InitUprobeSo(stopper <-chan struct{}) {

	//找到binPath中的符号的地址
	var symbolLocations []string
	var err error
	if config.ElfPath == "" {
		symbolLocations, err = utils.GetSoSymbol(config.SoPath)
		if err != nil {
			log.Fatalf("Error: %v", err)
		}
	} else {
		symbolLocations, err = utils.GetElfSoSymbol(config.ElfPath, config.SoPath)
		if err != nil {
			log.Fatalf("Error: %v", err)
		}
	}

	// Open an ELF binary and read its symbols.
	ex, err := link.OpenExecutable(config.SoPath)
	if err != nil {
		log.Fatalf("opening executable: %s", err)
	}

	resultChan := make(chan Event, len(symbolLocations))
	substopers := make([]chan struct{}, 0)

	//attach uprobe
	for k, v := range symbolLocations {
		substopper := make(chan struct{}, 1)
		go func(id int, sym string, mystopper <-chan struct{}, resultCh chan<- Event) {
			config.BpfProgsNum.Add(1)
			defer config.BpfProgsNum.Add(-1)

			objs := bpfObjects{}
			if err := loadBpfObjects(&objs, nil); err != nil {
				log.Fatalf("loading objects: %s", err)
			}
			defer objs.Close()

			up, err := ex.Uprobe(sym, objs.UprobeFunc, &link.UprobeOptions{
				// Address:       0, // 优化思路，在这里指定符号地址，仅hook elf文件
				// Offset:        0,
				PID: int(config.Pid),
			})
			if err != nil {
				// eg: sleep@GLIBC_2.2.5 failed to attach uprobe: cannot resolve BinPath library call not supported (consider providing UprobeOptions.Address)
				// ignore
				log.Printf("attaching uprobe: %v", err)
				return
			}
			defer up.Close()

			<-mystopper

			var value uint64
			if err := objs.FuncCount.Lookup(uint32(0), &value); err == nil && value != 0 {
				resultCh <- Event{
					Symbol: sym,
					Cnt:    value,
				}
			}
		}(k, v, substopper, resultChan)
		substopers = append(substopers, substopper)
	}

	log.Println("Counting packets. Press CTRL+C to stop")

	<-stopper
	log.Println("Exiting...")

	for _, v := range substopers {
		v <- struct{}{}
	}

	exitAndPrintResults(resultChan)
}
